﻿/**************************************************************************
创建时间:	2018/5/22
作	  者:	张存
邮 	  箱:	zhangcunliang@126.com

Copyright (c) zhcun.cn

描	述：字节数组转换的帮助类
记	录：
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace ZhCun.SerialIO.Utils
{
    public class BytesTools
    {
        public static string ByteArrToHex(byte[] cmd, int offset, int length, bool isAddEmpty = true)
        {
            //if (cmd == null || cmd.Length == 0) return null;
            StringBuilder sb = new StringBuilder();
            for (int i = offset; i < offset + length; i++)
            {
                sb.Append(cmd[i].ToString("X2"));
                if (isAddEmpty) sb.Append(" ");
            }
            return sb.ToString();
        }

        /// <summary>
        /// 字节数组转换成十六进制字符串,指定是否每个字节加一个空格
        /// </summary>
        public static string ByteArrToHex(byte[] cmd, bool isAddEmpty = true)
        {
            return ByteArrToHex(cmd, 0, cmd.Length, isAddEmpty);
        }
        /// <summary>
        /// 将16进制字符串转换成byte数组（）,每2个字符转换为1个byte
        /// </summary>
        public static byte[] HexToByteArr(string data)
        {
            data = data.Replace(" ", "");
            int count = data.Length;
            if (data.Length % 2 != 0)
            {
                count--;
                //throw new Exception("转换的数据格式不正确");
            }
            List<byte> dataList = new List<byte>();
            for (int i = 0; i < count; i += 2)
            {
                dataList.Add(Convert.ToByte(data.Substring(i, 2), 16));
            }
            return dataList.ToArray();
        }
        /// <summary>
        /// 查找指定数组的位置，未找到返回-1
        /// </summary>
        /// <param name="src">要查找的源数据</param>
        /// <param name="offset">源数据偏移量</param>
        /// <param name="count">源数据长度</param>
        /// <param name="tar">查找的目标数据</param>
        /// <returns>返回首次出现的位置</returns>
        public static int FindBytes(byte[] src, int offset, int count, params byte[] tar)
        {
            if (tar.Length == 0) return 0;
            int headOffset = -1;
            for (int i = 0; i <= count - tar.Length; i++)
            {
                for (int j = 0; j < tar.Length; j++)
                {
                    if (src[offset + i] != tar[j])
                    {
                        if (headOffset >= 0) i = headOffset - offset;
                        headOffset = -1;
                        break;
                    }
                    if (headOffset == -1) headOffset = offset + i;
                    i++;
                }
                if (headOffset >= 0) break;
            }

            return headOffset;
        }

        /// <summary>
        /// 根据偏移量长度获取新的完整数组
        /// </summary>
        public static byte[] GetSegmentBytes(byte[] buffer, int offset, int length)
        {
            byte[] rbs = new byte[length];
            for (int i = 0; i < length; i++)
            {
                rbs[i] = buffer[offset + i];
            }
            return rbs;
        }
        /// <summary>
        /// 低字节与高字节转换
        /// </summary>
        public static byte[] LittleToBigEndian(byte[] source, int startIndex, int count)
        {
            byte[] bs = new byte[count];
            for (int i = 0; i < count; i++)
            {
                bs[i] = source[count - 1 - i + startIndex];
            }
            return bs;
        }
        /// <summary>
        /// 将data数组的顺序翻转（高低位转换）
        /// </summary>
        public static byte[] Reverse(byte[] data)
        {
            byte tmp;
            for (int i = 0; i < data.Length / 2; i++)
            {
                tmp = data[i];
                data[i] = data[data.Length - 1 - i];
                data[data.Length - 1 - i] = tmp;
            }
            return data;
        }
        /// <summary>
        /// 低字节与高字节转换
        /// </summary>
        public static byte[] LittleToBigEndian(byte[] source)
        {
            return LittleToBigEndian(source, 0, source.Length);
        }
        /// <summary>
        /// 计算CRC校验码
        /// Cyclic Redundancy Check 循环冗余校验码
        /// 是数据通信领域中最常用的一种差错校验码
        /// 特征是信息字段和校验字段的长度可以任意选定
        /// </summary>
        public static byte[] CRC16_C(byte[] buffer, int startIndex, int endIndex)
        {
            byte num = 0xff;
            byte num2 = 0xff;

            byte num3 = 1;
            byte num4 = 160;
            //byte[] buffer = data;

            for (int i = startIndex; i <= endIndex; i++)
            {
                //if (i >= buffer.Length) break;  //如果超出范围，算了，还是抛出异常吧
                //位异或运算
                num = (byte)(num ^ buffer[i]);

                for (int j = 0; j <= 7; j++)
                {
                    byte num5 = num2;
                    byte num6 = num;

                    //位右移运算
                    num2 = (byte)(num2 >> 1);
                    num = (byte)(num >> 1);

                    //位与运算
                    if ((num5 & 1) == 1)
                    {
                        //位或运算
                        num = (byte)(num | 0x80);
                    }
                    if ((num6 & 1) == 1)
                    {
                        num2 = (byte)(num2 ^ num4);
                        num = (byte)(num ^ num3);
                    }
                }
            }
            return new byte[] { num, num2 };
        }
        /// <summary>
        /// 计算CRC校验码
        /// Cyclic Redundancy Check 循环冗余校验码
        /// 是数据通信领域中最常用的一种差错校验码
        /// 特征是信息字段和校验字段的长度可以任意选定
        /// </summary>
        public static byte[] CRC16_C(byte[] buffer)
        {
            return CRC16_C(buffer, 0, buffer.Length - 1);
        }
        /// <summary>
        /// 字节数组转换为单精度浮点（低字节在前，高字节在后）
        /// </summary>
        public static float BytesToFloat(byte[] data, int startIndex)
        {
            byte[] bs = LittleToBigEndian(data, startIndex, 4);
            float r = BitConverter.ToSingle(bs, 0);
            return r;
        }


        public static ushort CRC16ByRedundancy(byte[] data, int startIndex, int endIndex)
        {
            ushort crc = 0xFFFF;
            for (int i = startIndex; i <= endIndex; i++)
            {
                crc = (ushort)(crc >> 8 ^ data[i]);
                for (byte j = 0; j < 8; j++)
                {
                    int check = crc & 0x0001;
                    crc >>= 1;
                    if (check == 0x0001)
                    {
                        crc ^= 0xA001;
                    }
                }
            }
            return crc;
        }

        public static ushort HZCRC16ByNum(byte[] data, int startIndex, int endIndex)
        {
            //if (startIndex == 0) count = data.Length;
            ushort crc = 0;
            for (int i = startIndex; i <= endIndex; i++)
            {
                crc = (ushort)(crc ^ (data[i] << 8));
                for (byte j = 0; j < 8; j++)
                {
                    if ((crc & 0x8000) != 0)
                    {
                        crc = (ushort)((crc << 1) ^ 0x1021);
                    }
                    else crc <<= 1;
                }
            }
            return crc;
        }
        public static ushort HZCRC16ByNum(byte[] data)
        {
            return HZCRC16ByNum(data, 0, data.Length - 1);
        }
        public static byte[] HZCRC16(byte[] data, int startIndex, int endIndex)
        {
            var crc = HZCRC16ByNum(data, startIndex, endIndex);
            byte[] r = BitConverter.GetBytes(crc);
            return r;
        }
        public static byte[] HZCRC16(byte[] data)
        {
            return HZCRC16(data, 0, data.Length - 1);
        }

    }
}